#pragma once 
#include"sock.hpp"
#include<poll.h>

namespace ns_poll
{
    using namespace ns_sock;
    const int default_port=8081;
#define NUM 1024

    class Poll
    {
    private:
        uint16_t _port;
        int _listen_sock;
        struct pollfd fds[NUM];//保存需要关注的文件的对应文件描述符
    public:
        Poll(uint16_t port=default_port):_port(port),_listen_sock(-1){
            for(int i=0;i<NUM;i++) //初始化需要关心的文件数组
            {
                fds[i].fd=-1;
                fds[i].events=0;
                fds[i].revents=0;
            }
        }
        ~Poll(){
            if(_listen_sock>=0) close(_listen_sock);
        }
        void InitPollServer()
        {
            _listen_sock=Sock::Socket();
            Sock::Bind(_listen_sock,_port);
            Sock::Listen(_listen_sock);
            //将监听套接字保存
            fds[0].fd=_listen_sock;
            fds[0].events=POLLIN;//关心读事件
        }
        void PrintFd()
        {   
            std::cout<<"poll_fds:";
            for(int i=0;i<NUM;i++)
            {
                if(fds[i].fd!=-1)
                    std::cout<<fds[i].fd<<" ";
            }
            std::cout<<std::endl;;
        }
        void HandlerEvent()
        {
            //poll依旧需要进行遍历查询就绪事件
            for(int i=0;i<NUM;i++)
            {
                if(fds[i].fd==-1) continue;
                if(fds[i].revents&POLLIN){
                    if(fds[i].fd==_listen_sock){//连接到来
                        struct sockaddr_in peer;
                        socklen_t len=sizeof(peer);
                        bzero(&peer,len);
                        int sock=accept(_listen_sock,(struct sockaddr*)&peer,&len);
                        if(sock>0){
                            //添加文件描述符
                            int j=0;
                            for(;j<NUM;j++)
                            {
                                if(fds[j].fd>0) continue;
                                if(fds[j].fd==-1){
                                    fds[j].fd=sock;
                                    fds[j].events=POLLIN;//设置关心读事件
                                    break;
                                }
                            }
                            if(j==NUM){
                                std::cerr<<"poll_fds 已满"<<std::endl;
                                close(sock);//关闭文件
                            }
                            else{
                                std::cout<<"新连接到来:"<<sock<<std::endl;
                                PrintFd();
                            }
                        }else{
                            std::cerr<<"accept err"<<std::endl;
                            //异常处理...
                        }
                    }
                    else{//数据到来-进行数据读取
                        char buffer[1024]={0};
                        ssize_t s=recv(fds[i].fd,buffer,sizeof(buffer),0);
                        if(s>0){
                            buffer[s-1]=0;
                            std::cout<<"buffer:"<<buffer<<std::endl;
                        }else if(s==0){//对端连接关闭
                            std::cerr<<"peer sock:"<<fds[i].fd<<" close..."<<std::endl;
                            close(fds[i].fd);//关闭连接
                            fds[i].fd=-1;//去除保存的数据
                            fds[i].events=0;
                            fds[i].revents=0;
                            PrintFd();
                        }else{
                            std::cerr<<"recv err..."<<std::endl;
                        }
                    }
                }
            }
        }
        void Loop()
        {
            while(true){
                //poll的输入输出参数是分离的，所以这里不用每次都进行初始化文件数组
                //多路转接
                int time=-1;//阻塞式
                int n=poll(fds,NUM,time);//有数据拷贝到内核的消耗
                if (n>0)//有事件就绪
                    HandlerEvent();
                else if(n==0)
                    std::cout<<"timeout..."<<std::endl;
                else
                    std::cerr<<"poll err"<<errno<<std::endl;          
            }
        }
    } ;
}